package com.token.sysflow.hander;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.token.sql.IntegrateSql;
import com.token.sql.PrepareSql;

import com.token.sysflow.bean.*;
import com.token.sysflow.enumerate.StepApproverTypeEnum;
import com.token.sysflow.enumerate.StepTypeEnum;
import com.token.sysflow.exception.ErrorCodeEnum;
import com.token.sysflow.exception.FlowException;
import com.token.sysflow.impl.AbstractFlowHandlerImpl;
import com.token.sysorg.bean.*;
import lombok.Getter;
import lombok.Setter;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;

/**
 * 流程配置中的办理人计算
 *
 * @author chenjianxiong  2020/5/4
 */
public class StepApprover {
    private final PrepareSql pSql;
    private final FlowStepApprover flowStepApprover;

    @Getter
    private final ArrayList<String> userId;

    @Getter
    private final JSONArray approvers;

    @Setter
    private AbstractFlowHandlerImpl flowHandlerImpl;

    @Setter
    private ApproveProcess process;

    @Setter
    private String applyer;

    @Setter
    private String creater;

    private final Step curStep;

    public StepApprover(IntegrateSql iSql, Step step) throws Exception {
        pSql = new PrepareSql(iSql);
        flowStepApprover = new FlowStepApprover(iSql, step.getStepId());
        curStep = step;
        userId = new ArrayList<>();
        approvers = new JSONArray();

    }

    public void execute() throws Exception {

        //当前环节是子流程
        String StepType = curStep.getStepType();
        if (StepType.equals(StepTypeEnum.STEPTYPE_END.getTypeKey())) { //结束环节
            userId.add("*");
            add("*", "*", "*");
        } else {
            if (StepTypeEnum.STEPTYPE_TASK_ZLC.getTypeKey().equals(StepType)) {
                stepApproversToArray_sub();
            } else {
                stepApproversToArray();
            }
        }
    }

    /**
     * 获取用户数组
     *
     * @return
     */
    public String[] getUserIdArray() {
        return userId.toArray(new String[userId.size()]);
    }


    /**
     * 获取办理人
     *
     * @return String
     */
    private void stepApproversToArray() throws Exception {

        StringBuffer sql = new StringBuffer(200);
        int approverType = flowStepApprover.getApproverType();
        StepApproverTypeEnum stepApproverTypeEnum = StepApproverTypeEnum.getTypeByValue(approverType);
        System.out.println("--->办理人设置：" + stepApproverTypeEnum);
        ResultSet rs;
        switch (Objects.requireNonNull(stepApproverTypeEnum)) {
            case PERSON:
                //配置-->用户+岗位
                sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                        .append(FlowStepApproverVth.TABLE_NAME)
                        .append(" vth left join ")
                        .append(FSysPersonnel.TABLE_NAME)
                        .append(" user on vth.Value = user.PersonNumber ")
                        .append(" left join ")
                        .append(FSysPost.TABLE_NAME)
                        .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId ")
                        .append(" where user.SysId=? and vth.FieldName=? and vth.StepId=?");
                pSql.setPrepare(sql);
                pSql.setPstValue(1, flowHandlerImpl.getSysId());
                pSql.setPstValue(2, stepApproverTypeEnum.getFieldName());
                pSql.setPstValue(3, flowStepApprover.getStepId());
                break;
            case POST:
                //配置-->岗位-->用户
                sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                        .append(FlowStepApproverVth.TABLE_NAME)
                        .append(" vth left join ")
                        .append(FSysPost.TABLE_NAME)
                        .append(" post on vth.Value = post.PostNumber ")
                        .append(" inner join ")
                        .append(FSysPersonnel.TABLE_NAME)
                        .append(" user on post.PostNumber = user.PostID and user.SysId=post.SysId ")
                        .append(" where post.SysId=? and vth.FieldName=? and vth.StepId=? order by post.PostId");
                pSql.setPrepare(sql);
                pSql.setPstValue(1, flowHandlerImpl.getSysId());
                pSql.setPstValue(2, stepApproverTypeEnum.getFieldName());
                pSql.setPstValue(3, flowStepApprover.getStepId());
                break;
            case ROLE:
                if (flowStepApprover.getRoleOrPerson().equals("0")) { //角色名称
                    sql.append("select vth.Value as id,role.RoleName as name,'' as postName from ")
                            .append(FlowStepApproverVth.TABLE_NAME)
                            .append(" vth left join ")
                            .append(FSysRole.TABLE_NAME)
                            .append(" role on vth.Value = role.RoleNumber and role.SysId=?")
                            .append(" where vth.FieldName=? and vth.StepId=? ");
                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, stepApproverTypeEnum.getFieldName());
                    pSql.setPstValue(3, flowStepApprover.getStepId());

                } else { //角色成员
                    //配置-->角色成员-->人员 + 岗位
                    sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                            .append(FlowStepApproverVth.TABLE_NAME) // 配置
                            .append(" vth inner join ")
                            .append(fsysroleMember.TABLE_NAME) // 角色成员
                            .append(" member on vth.value = member.RoleNumber ")
                            .append(" inner join ")
                            .append(FSysPersonnel.TABLE_NAME) //人员
                            .append(" user on member.RoleMemberNumber = user.PersonNumber and member.SysId=user.SysId ")
                            .append(" inner join ")
                            .append(FSysPost.TABLE_NAME) //岗位
                            .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId")
                            .append(" where member.SysId=? and user.SysId=? and vth.FieldName=? and vth.StepId=? and member.RoleMemberType=2 "); //人员

                    sql.append(" UNION ALL ");
//                    pSql.setPrepare(sql);
//                    pSql.setPstValue(1, stepApproverTypeEnum.getFieldName());
//                    pSql.setPstValue(2, flowStepApprover.getStepId());
//                    addRs(pSql.executeQuery());
//                    pSql.close();


                    //配置-->角色成员-->岗位-->人员
//                    sql = new StringBuffer(100);
                    sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                            .append(FlowStepApproverVth.TABLE_NAME) // 配置
                            .append(" vth inner join ")
                            .append(fsysroleMember.TABLE_NAME) // 角色成员
                            .append(" member on vth.Value = member.RoleNumber ")
                            .append(" inner join ")
                            .append(FSysPost.TABLE_NAME) //岗位
                            .append(" post on member.RoleMemberNumber=post.PostNumber and member.SysId=post.SysId ")
                            .append(" inner join ")
                            .append(FSysPersonnel.TABLE_NAME) //人员
                            .append(" user on member.RoleMemberNumber = user.PostId and user.SysId=member.SysId")
                            .append(" where member.SysId=? and vth.FieldName=? and vth.StepId=? and member.RoleMemberType=1"); //岗位
                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, flowHandlerImpl.getSysId());
                    pSql.setPstValue(3, stepApproverTypeEnum.getFieldName());
                    pSql.setPstValue(4, flowStepApprover.getStepId());

                    pSql.setPstValue(5, flowHandlerImpl.getSysId());
                    pSql.setPstValue(6, stepApproverTypeEnum.getFieldName());
                    pSql.setPstValue(7, flowStepApprover.getStepId());
                }

                break;
            case FIELD:
                JSONArray array = new JSONArray();
                JSONObject json = flowHandlerImpl.getFieldValues();
                if (json.size() == 0) {
                    throw new FlowException(ErrorCodeEnum.PARA_FIELDVALUES_NOFIND);
                }
                sql.append("select vth.value from ")
                        .append(FlowStepApproverVth.TABLE_NAME)
                        .append(" vth where vth.FieldName=? and vth.StepId=?");
                pSql.setPrepare(sql);
                pSql.setPstValue(1, stepApproverTypeEnum.getFieldName());
                pSql.setPstValue(2, flowStepApprover.getStepId());
//                System.out.println("sql = " + sql);
//                System.out.println("stepApproverTypeEnum.getFieldName() = " + stepApproverTypeEnum.getFieldName());
//                System.out.println("flowStepApprover.getStepId() = " + flowStepApprover.getStepId());
                rs = pSql.executeQuery();
                if (rs.next()) {

                    JSONArray array2;
                    do {
                        array2 = json.getJSONArray(rs.getString("value"));
                        if (array2 != null) {
                            array.addAll(array2);
                        }
                    } while (rs.next());

                } else {
                    throw new FlowException(ErrorCodeEnum.CONFIG_APPROVERFIELD);
                }
                rs.close();
                pSql.close();

                //---读取数据
                int size = array.size();
                if (size > 0) {
                    sql = new StringBuffer(200);
                    sql.append(getUserDataSql())
                            .append(" where user.SysId=? and user.PersonNumber in(")
                            .append(String.join(",", Collections.nCopies(size, "?")))
                            .append(")");
                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    for (int j = 0; j < size; j++) {
                        pSql.setPstValue(j + 2, array.getString(j));
                    }
                } else {
                    throw new FlowException(ErrorCodeEnum.PARA_FIELDVALUE_NOFIND);
                }

                break;
            case STEP:
                if (flowStepApprover.getPreHandlerSw() && !"".equals(flowStepApprover.getPreHandler())) {
                    if (process == null) { //可能是起草环节提交，取当前操作用户
                        sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                                .append(FSysPersonnel.TABLE_NAME)
                                .append(" user left join ")
                                .append(FSysPost.TABLE_NAME)
                                .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId ")
                                .append(" where user.SysId=? and user.PersonNumber=?");
                        pSql.setPrepare(sql);
                        pSql.setPstValue(1, flowHandlerImpl.getSysId());
                        pSql.setPstValue(2, flowHandlerImpl.getActionUser());
                    } else {
                        sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                                .append(FSysFlowRecord.TABLE_NAME)
                                .append(" vth left join ")
                                .append(FSysPersonnel.TABLE_NAME)
                                .append(" user on vth.Value = user.PersonNumber ")
                                .append(" left join ")
                                .append(FSysPost.TABLE_NAME)
                                .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId")
                                .append(" where user.SysId=? and vth.KeyUnid=? and vth.StepId=?");
                        pSql.setPrepare(sql);
                        pSql.setPstValue(1, flowHandlerImpl.getSysId());
                        pSql.setPstValue(2, process.getKeyUnid());
                        pSql.setPstValue(3, flowStepApprover.getStepId());
                    }

                } else {
                    throw new FlowException(ErrorCodeEnum.CONFIG_PREHANDLERSW);
                }
                break;
            case ORG:
                if (flowStepApprover.getDeptLeaderSw()) {
                    if (process != null) {
                        this.applyer = process.getApplyer();
                        this.creater = process.getCreater();
                    }

                    switch (flowStepApprover.getDeptLeader()) {
                        case 1://部门领导

                            sql.append("select LeaderId from ").append(FSysDepartment.TABLE_NAME)
                                    .append(" where SysID=? and DepartmentNumber in(select DeptID from ")
                                    .append(FSysPersonnel.TABLE_NAME).append(" where SysID=? and PersonNumber=?)");
                            break;
                        case 2://分管领导
                            sql.append("select InChargeLeaderID from ").append(FSysDepartment.TABLE_NAME)
                                    .append(" where SysID=? and DepartmentNumber in(select DeptID from ")
                                    .append(FSysPersonnel.TABLE_NAME).append(" where SysID=? and PersonNumber=?)");
                            break;
                        case 3://公司领导
                            sql.append("select LeaderID from ").append(FSysUnit.TABLE_NAME)
                                    .append(" where SysID=? and UnitID in(select ComID from ")
                                    .append(FSysPersonnel.TABLE_NAME).append(" where SysID=? and PersonNumber=?)");
                            break;
                        default:
                            throw new FlowException(ErrorCodeEnum.CONFIG_DEPTLEADERSW_D);
                    }

                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, flowHandlerImpl.getSysId());
                    String user, leader;
                    switch (flowStepApprover.getDeptLeaderTy()) {
                        case 1: //起草人
                            user = this.creater;
                            break;
                        case 2: //申请人
                            user = this.applyer;
                            break;
                        case 3: //当前人
                            user = flowHandlerImpl.getActionUser();
                            break;
                        default:
                            throw new FlowException(ErrorCodeEnum.CONFIG_DEPTLEADERSW_R);
                    }
                    pSql.setPstValue(3, user);
                    rs = pSql.executeQuery();
                    if (rs.next()) {
                        leader = rs.getString(1);
                    } else {
                        throw new FlowException(ErrorCodeEnum.ORG_USER_ERROR, user);
                    }
                    rs.close();
                    pSql.close();

                    sql = new StringBuffer(100);
                    sql.append(getUserDataSql());
                    sql.append(" where user.SysId=? and user.PersonNumber=? ");
                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, leader);

                } else {
                    throw new FlowException(ErrorCodeEnum.CONFIG_DEPTLEADERSW);
                }
                break;
            case FUNCTION:
                if(flowStepApprover.getApproverFunc().equals("")){
                    throw new FlowException(ErrorCodeEnum.CONFIG_APPROVERFUNC);
                }else {

                    StringBuffer userSql = new StringBuffer(50);
                    String user,returnField,option;

                    if(flowStepApprover.getApproverFuncOrg() == 1){ //部门
                        returnField = "DeptID";
                    }else if(flowStepApprover.getApproverFuncOrg() == 2) { //公司
                        returnField = "ComID";
                    }else{
                        throw new FlowException(ErrorCodeEnum.CONFIG_APPROVERFUNC_ORG);
                    }

                    switch (flowStepApprover.getApproverFuncTy()) {
                        case 1: //起草人
                            user = this.creater;
                            break;
                        case 2: //申请人
                            user = this.applyer;
                            break;
                        case 3: //当前人
                           user = flowHandlerImpl.getActionUser();
                            break;
                        default:
                            throw new FlowException(ErrorCodeEnum.CONFIG_DEPTLEADERSW_R);
                    }

                    userSql.append("select ").append(returnField)
                            .append(" from ")
                            .append(FSysPersonnel.TABLE_NAME)
                            .append(" where SysId=? and PersonNumber=? ");

                    pSql.setPrepare(userSql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, user);
                    rs = pSql.executeQuery();
                    if(rs.next()) {
                        option = rs.getString(1);
                    }else{
                        throw new FlowException(ErrorCodeEnum.APPROVERFUNC_ERROR);
                    }
                    rs.close();
                    pSql.close();

                    System.out.println("--->option:" + option + " user:" + user + " role:" + flowStepApprover.getApproverFunc());
                    //人员
                    sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                            .append(fsysroleMember.TABLE_NAME) // 角色成员
                            .append(" member")
                            .append(" inner join ")
                            .append(FSysPersonnel.TABLE_NAME) //人员
                            .append(" user on member.RoleMemberNumber = user.PersonNumber and member.SysId=?")
                            .append(" inner join ")
                            .append(FSysPost.TABLE_NAME) //岗位
                            .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId ")
                            .append(" where member.RoleMemberType=2 and member.RoleNumber=? and user.") //人员
                            .append(returnField).append("=?")
                            .append("and user.SysId=").append(flowHandlerImpl.getSysId());
                    sql.append(" UNION ALL ");

                    //岗位
                    sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                            .append(fsysroleMember.TABLE_NAME) // 角色成员
                            .append(" member ")
                            .append(" inner join ")
                            .append(FSysPost.TABLE_NAME) //岗位
                            .append(" post on member.RoleMemberNumber=post.PostNumber and member.SysId=?")
                            .append(" inner join ")
                            .append(FSysPersonnel.TABLE_NAME) //人员
                            .append(" user on member.RoleMemberNumber=user.PostId and user.SysId=post.SysId")
                            .append(" where member.RoleMemberType=1 and member.RoleNumber=? and user.") //岗位
                            .append(returnField).append("=? ")
                            .append("and user.SysId=").append(flowHandlerImpl.getSysId());
                    pSql.setPrepare(sql);
                    pSql.setPstValue(1, flowHandlerImpl.getSysId());
                    pSql.setPstValue(2, flowStepApprover.getApproverFunc());
                    pSql.setPstValue(3, option);

                    pSql.setPstValue(4, flowHandlerImpl.getSysId());
                    pSql.setPstValue(5, flowStepApprover.getApproverFunc());
                    pSql.setPstValue(6, option);
                }
                break;
            case FORMULA:
                //TODO 办理人公式的计算
                break;
            default:
                throw new FlowException(ErrorCodeEnum.STEPAPPROVERTYPE_NOFIND);
        }

//        System.out.println("sql  = " + sql);
        addRs(pSql.executeQuery());

    }

    /**
     * @return
     */
    private StringBuffer getUserDataSql() {
        StringBuffer sql = new StringBuffer(100);
        sql.append("select user.PersonNumber as id,user.PersonName as name,post.PostName from ")
                .append(FSysPersonnel.TABLE_NAME)
                .append(" user left join ")
                .append(FSysPost.TABLE_NAME)
                .append(" post on user.PostId=post.PostNumber and user.SysId=post.SysId ");
//        sql.append(where);
        return sql;
    }

    /**
     * @param rs
     * @throws Exception 抛出错误
     */
    private void addRs(ResultSet rs) throws Exception {
        if (rs.next()) {
            do {
                userId.add(rs.getString("id"));
                add(rs.getString("id"), rs.getString("name"), rs.getString("postName"));
            } while (rs.next());
        }
        rs.close();
    }

    /**
     * @param id
     * @param name
     * @param postName
     */
    private void add(String id, String name, String postName) {
        JSONObject json = new JSONObject();
        json.put("id", id);
        if (name == null) {
            json.put("name", "[找不到 " + id + " 对应数据]");
            json.put("isHas", false);
        } else {
            json.put("name", name);
            json.put("isHas", true);
        }

        json.put("postName", postName);
        approvers.add(json);
    }

    /**
     * @throws Exception 抛出错误
     */
    private void stepApproversToArray_sub() throws Exception {
        SubFlow subFlow = new SubFlow(flowStepApprover.getIntegrateSql(), flowStepApprover.getStepId());
        //[{approver:[],subName:"",subId:""}]
        ArrayList<JSONObject> arrayList = subFlow.getFlowSubApprovers();
        JSONObject json;
        JSONArray approver;

        int size;
        StringBuffer sql;

        for (int i = 0; i < arrayList.size(); i++) {
            json = arrayList.get(i);
//            System.out.println("stepApproversToArray_sub = " + json);
            approver = json.getJSONArray("approver");
            size = approver.size();
            sql = new StringBuffer(100);
            sql.append(getUserDataSql())
                    .append(" where user.SysId=? and user.PersonNumber in(")
                    .append(String.join(",", Collections.nCopies(size, "?"))).append(")");
            pSql.setPrepare(sql);
            pSql.setPstValue(1, flowHandlerImpl.getSysId());
            for (int j = 0; j < size; j++) {
                pSql.setPstValue(j + 2, approver.getString(j));
            }

            ResultSet rs = pSql.executeQuery();

            if (rs.next()) {
                ArrayList<String> aId = new ArrayList<>();
                ArrayList<String> aName = new ArrayList<>();
                do {
                    userId.add(rs.getString("id"));
                    aId.add(rs.getString("id"));
                    aName.add(rs.getString("name"));
                } while (rs.next());
                add(json.getString("subId")+"|"+ String.join(",",aId), json.getString("subName")+"("+ String.join(",",aName) +")", "");
            }else{
                throw new FlowException(ErrorCodeEnum.PREHANDLERSW_NOFIND);
            }
            rs.close();

            pSql.close();
        }
        subFlow.close();

    }

    /**
     *
     */
    public void close() {
        try {
            flowStepApprover.close();
            pSql.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
